/*
 * AAC Spectral Band Replication function declarations
 * Copyright (c) 2008-2009 Robert Swain ( rob opendot cl )
 * Copyright (c) 2010      Alex Converse <alex.converse@gmail.com>
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
 * @file
 * AAC Spectral Band Replication function declarations
 * @author Robert Swain ( rob opendot cl )
 */

#ifndef AVCODEC_AACSBR_H
#define AVCODEC_AACSBR_H
#include "get_bits.h"
#include "sbr.h"
#include "aac.h"
#undef rint
#define rint(x) ceill((x))

#if !HAVE_LOG2
#undef log2
#define log2(x) (log(x) * 1.44269504088896340736)
#endif /* HAVE_LOG2 */

#if !HAVE_LOG2F
#undef log2f
#define log2f(x) ((float)log2(x))
#endif /* HAVE_LOG2F */

#define ENVELOPE_ADJUSTMENT_OFFSET 2
#define NOISE_FLOOR_OFFSET 6.0f

#if !HAVE_EXP2
#undef exp2
#define exp2(x) exp((x) * 0.693147180559945)
#endif /* HAVE_EXP2 */

#if !HAVE_EXP2F
#undef exp2f
#define exp2f(x) ((float)exp2(x))
#endif /* HAVE_EXP2F */

enum {T_HUFFMAN_ENV_1_5DB,F_HUFFMAN_ENV_1_5DB,T_HUFFMAN_ENV_BAL_1_5DB,F_HUFFMAN_ENV_BAL_1_5DB,T_HUFFMAN_ENV_3_0DB,F_HUFFMAN_ENV_3_0DB,T_HUFFMAN_ENV_BAL_3_0DB,F_HUFFMAN_ENV_BAL_3_0DB,T_HUFFMAN_NOISE_3_0DB,T_HUFFMAN_NOISE_BAL_3_0DB};
enum {FIXFIX,FIXVAR,VARFIX,VARVAR};
enum {EXTENSION_ID_PS = 2};
static VLC vlc_sbr[10];
static const int8_t vlc_sbr_lav[10];
static const DECLARE_ALIGNED(16, float, zero64)[64];
#define SBR_INIT_VLC_STATIC(num, size) \
	INIT_VLC_STATIC(&vlc_sbr[num], 9, sbr_tmp[num].table_size / sbr_tmp[num].elem_size,     \
	sbr_tmp[num].sbr_bits ,                      1,                      1, \
	sbr_tmp[num].sbr_codes, sbr_tmp[num].elem_size, sbr_tmp[num].elem_size, \
	size)
#define SBR_VLC_ROW(name) \
{ name ## _codes, name ## _bits, sizeof(name ## _codes), sizeof(name ## _codes[0]) }
av_cold void ff_aac_sbr_init(void);
av_cold void ff_aac_sbr_ctx_init(SpectralBandReplication *sbr);
av_cold void ff_aac_sbr_ctx_close(SpectralBandReplication *sbr);
static int qsort_comparison_function_int16(const void *a, const void *b);
static inline int in_table_int16(const int16_t *table, int last_el, int16_t needle);
static void sbr_make_f_tablelim(SpectralBandReplication *sbr);
static unsigned int read_sbr_header(SpectralBandReplication *sbr, GetBitContext *gb);
static int array_min_int16(const int16_t *array, int nel);
static void make_bands(int16_t* bands, int start, int stop, int num_bands);
static int check_n_master(AVCodecContext *avctx, int n_master, int bs_xover_band);
static int sbr_make_f_master(AACContext *ac, SpectralBandReplication *sbr,SpectrumParameters *spectrum);
static int sbr_hf_calc_npatches(AACContext *ac, SpectralBandReplication *sbr);
static int sbr_make_f_derived(AACContext *ac, SpectralBandReplication *sbr);
static av_always_inline void get_bits1_vector(GetBitContext *gb, uint8_t *vec,int elements);
static const int8_t ceil_log2[] ={
	0, 1, 2, 2, 3, 3,
};
static int read_sbr_grid(AACContext *ac, SpectralBandReplication *sbr,GetBitContext *gb, SBRData *ch_data);
static void copy_sbr_grid(SBRData *dst, const SBRData *src);
static void read_sbr_dtdf(SpectralBandReplication *sbr, GetBitContext *gb,SBRData *ch_data);
static void read_sbr_invf(SpectralBandReplication *sbr, GetBitContext *gb,SBRData *ch_data);
static void read_sbr_envelope(SpectralBandReplication *sbr, GetBitContext *gb,SBRData *ch_data, int ch);
static void read_sbr_noise(SpectralBandReplication *sbr, GetBitContext *gb,SBRData *ch_data, int ch);
static void read_sbr_extension(AACContext *ac, SpectralBandReplication *sbr,GetBitContext *gb,int bs_extension_id, int *num_bits_left);
static int read_sbr_single_channel_element(AACContext *ac,SpectralBandReplication *sbr,GetBitContext *gb);
static int read_sbr_channel_pair_element(AACContext *ac,SpectralBandReplication *sbr,GetBitContext *gb);
static unsigned int read_sbr_data(AACContext *ac, SpectralBandReplication *sbr,GetBitContext *gb, int id_aac);
static void sbr_reset(AACContext *ac, SpectralBandReplication *sbr);
int ff_decode_sbr_extension(AACContext *ac, SpectralBandReplication *sbr,GetBitContext *gb_host, int crc, int cnt, int id_aac);
static void sbr_dequant(SpectralBandReplication *sbr, int id_aac);
static void sbr_qmf_analysis(DSPContext *dsp, FFTContext *mdct, const float *in, float *x,float z[320], float W[2][32][32][2],float scale);
static void sbr_qmf_synthesis(DSPContext *dsp, FFTContext *mdct,float *out, float X[2][38][64],float mdct_buf[2][64],float *v0, int *v_off, const unsigned int div,float bias, float scale);
static void autocorrelate(const float x[40][2], float phi[3][2][2], int lag);
static void sbr_hf_inverse_filter(float (*alpha0)[2], float (*alpha1)[2],const float X_low[32][40][2], int k0);
static void sbr_chirp(SpectralBandReplication *sbr, SBRData *ch_data);
static int sbr_lf_gen(AACContext *ac, SpectralBandReplication *sbr,float X_low[32][40][2], const float W[2][32][32][2]);
static int sbr_hf_gen(AACContext *ac, SpectralBandReplication *sbr,float X_high[64][40][2], const float X_low[32][40][2],const float (*alpha0)[2], const float (*alpha1)[2],const float bw_array[5], const uint8_t *t_env,int bs_num_env);
static int sbr_x_gen(SpectralBandReplication *sbr, float X[2][38][64],const float X_low[32][40][2], const float Y[2][38][64][2],int ch);
static void sbr_mapping(AACContext *ac, SpectralBandReplication *sbr,SBRData *ch_data, int e_a[2]);
static void sbr_env_estimate(float (*e_curr)[48], float X_high[64][40][2],SpectralBandReplication *sbr, SBRData *ch_data);
static void sbr_gain_calc(AACContext *ac, SpectralBandReplication *sbr,SBRData *ch_data, const int e_a[2]);
static void sbr_hf_assemble(float Y[2][38][64][2], const float X_high[64][40][2],SpectralBandReplication *sbr, SBRData *ch_data,const int e_a[2]);
void ff_sbr_apply(AACContext *ac, SpectralBandReplication *sbr, int id_aac,float* L, float* R);

#endif /* AVCODEC_AACSBR_H */
